/***********************************************************************************************//**
 * \file   main.c
 * \brief  Silicon Labs Empty Example Project
 *
 * This example demonstrates the bare minimum needed for a Blue Gecko C application
 * that allows Over-the-Air Device Firmware Upgrading (OTA DFU). The application
 * starts advertising after boot and restarts advertising after a connection is closed.
 ***************************************************************************************************
 * <b> (C) Copyright 2016 Silicon Labs, http://www.silabs.com</b>
 ***************************************************************************************************
 * This file is licensed under the Silabs License Agreement. See the file
 * "Silabs_License_Agreement.txt" for details. Before using this software for
 * any purpose, you must agree to the terms of that agreement.
 **************************************************************************************************/

#ifndef GENERATION_DONE
#error You must run generate first!
#endif

/* Board headers */
#include "boards.h"
#include "ble-configuration.h"
#include "board_features.h"

/* Bluetooth stack headers */
#include "bg_types.h"
#include "native_gecko.h"
#include "gatt_db.h"
#include "aat.h"

/* Libraries containing default Gecko configuration values */
#include "em_emu.h"
#include "em_cmu.h"
#ifdef FEATURE_BOARD_DETECTED
#include "bspconfig.h"
#include "pti.h"
#endif

/* Device initialization header */
#include "InitDevice.h"

#ifdef FEATURE_SPI_FLASH
#include "em_usart.h"
#include "mx25flash_spi.h"
#endif /* FEATURE_SPI_FLASH */


/***********************************************************************************************//**
 * @addtogroup Application
 * @{
 **************************************************************************************************/

/***********************************************************************************************//**
 * @addtogroup app
 * @{
 **************************************************************************************************/

#ifndef MAX_CONNECTIONS
#define MAX_CONNECTIONS 4
#endif
uint8_t bluetooth_stack_heap[DEFAULT_BLUETOOTH_HEAP(MAX_CONNECTIONS)];

#ifdef FEATURE_PTI_SUPPORT
static const RADIO_PTIInit_t ptiInit = RADIO_PTI_INIT;
#endif

/* Gecko configuration parameters (see gecko_configuration.h) */
static const gecko_configuration_t config = {
  .config_flags=0,
  .sleep.flags = SLEEP_FLAGS_ENABLE_WAKEUP_PIN,//SLEEP_FLAGS_DEEP_SLEEP_ENABLE,
  .sleep.port = 2,
  .sleep.pin = 11,
  .bluetooth.max_connections=MAX_CONNECTIONS,
  .bluetooth.heap=bluetooth_stack_heap,
  .bluetooth.heap_size=sizeof(bluetooth_stack_heap),
  .bluetooth.sleep_clock_accuracy = 100, // ppm
  .gattdb=&bg_gattdb_data,
  .ota.flags=0,
  .ota.device_name_len=3,
  .ota.device_name_ptr="OTA",
  #ifdef FEATURE_PTI_SUPPORT
  .pti = &ptiInit,
  #endif
};

#include "infrastructure.h"
#include "bleusart.h"
/** Timer Frequency used. */
#define TIMER_CLK_FREQ ((uint32)32768)
/** Convert msec to timer ticks. */
#define TIMER_MS_2_TIMERTICK(ms) ((TIMER_CLK_FREQ * ms) / 1000)
/** Stop timer. */
#define TIMER_STOP 0

/* Flag for indicating DFU Reset must be performed */
uint8_t boot_to_dfu = 0;
uint8_t conConnectionId = 0xff;

/** R-R Interval measurement. */
typedef struct {
  uint16_t rRIntervalBuffer[7];    /**< RR-Interval */
  uint8_t rRIntervalLength;      /**< RR-Interval */
} hrRrInterval_t;
/** Heart Rate measurement structure. */
typedef struct {
  uint16_t hrMeasVal;            /**< Heart Rate Measurement Value */
  uint8_t flags;                 /**< Flags */
  uint16_t energyExpended;       /**< Energy Expended */
  hrRrInterval_t rRInterval;     /**< RR-Interval */
} hrHeartRateMeas_t;
static hrHeartRateMeas_t hrHeartRateMeas; /* Heart Rate Measurement */


static uint8_t hrBuildMeas(uint8_t *pBuf)
{
  uint8_t i;
  uint8_t *p = pBuf;
  uint8_t flags = hrHeartRateMeas.flags;

  /* Feed HR Measurement flags into the buffer */
  UINT8_TO_BITSTREAM(p, flags);

  /* Feed Heart Rate Measurement characteristic's fields into the buffer if corresponding field is
   * present */
  if (flags & 1)
  {
    UINT16_TO_BITSTREAM(p, hrHeartRateMeas.hrMeasVal);
  }
  else
  {
    UINT8_TO_BITSTREAM(p, (uint8_t)hrHeartRateMeas.hrMeasVal);
  }

  if (flags & 0x08)
  {
    UINT16_TO_BITSTREAM(p, hrHeartRateMeas.energyExpended);
  }

  /* time stamp field present */
  if (flags &  0x10)
  {
    for (i = 0; i < hrHeartRateMeas.rRInterval.rRIntervalLength; i++)
    {
      UINT16_TO_BITSTREAM(p,hrHeartRateMeas.rRInterval.rRIntervalBuffer[i]);
    }
  }

  return (uint8_t)(p - pBuf); /* return length of data to be sent */
}

static uint8_t hrProcess(uint8_t *buf)
{
  int8_t len;

  /* Update module global variables needed for Heart Rate measurement based on sensor values */
  hrHeartRateMeas.hrMeasVal = hrm;

  if (hrHeartRateMeas.flags & 0x08)
  {
    hrHeartRateMeas.energyExpended = elc;
  }

  if (hrHeartRateMeas.flags &  0x10)
  {
   //RRI
  }

  len = hrBuildMeas(buf);  /* Build heart rate measurement characteristic */

  return len;
}

void hrMeasure(void)
{
	if (0xff == conConnectionId)	return;
	uint8_t hrTempBuffer[2] = {0},length = 2;
	//length = hrProcess(hrTempBuffer);
	hrTempBuffer[0] = 2;
	hrTempBuffer[1] = hrm;
	gecko_cmd_gatt_server_send_characteristic_notification(0xff, gattdb_heart_rate_measurement, length, hrTempBuffer);
	gecko_cmd_gatt_server_write_attribute_value(gattdb_heart_rate_measurement,0,length,hrTempBuffer);
}

void batMeasure(void)
{
	gecko_cmd_gatt_server_send_characteristic_notification(0xff,gattdb_battery_level, sizeof(elc), &elc);
	gecko_cmd_gatt_server_write_attribute_value(gattdb_battery_level,0, sizeof(elc), &elc);
}
/**
 * @brief  Main function
 */
int main(void)
{
#ifdef FEATURE_SPI_FLASH
  /* Put the SPI flash into Deep Power Down mode for those radio boards where it is available */
  MX25_init();
  MX25_DP();
  /* We must disable SPI communication */
  USART_Reset(USART1);

#endif /* FEATURE_SPI_FLASH */

  /* Initialize peripherals */
  enter_DefaultMode_from_RESET();

  /* Initialize stack */
  gecko_init(&config);

  while (1) {
    /* Event pointer for handling events */
    struct gecko_cmd_packet* evt;
    
    /* Check for stack event. */
    evt = gecko_wait_event();

    /* Handle events */
    switch (BGLIB_MSG_ID(evt->header)) {

      /* This boot event is generated when the system boots up after reset.
       * Here the system is set to start advertising immediately after boot procedure. */
      case gecko_evt_system_boot_id:

        /* Set advertising parameters. 100ms advertisement interval. All channels used.
         * The first two parameters are minimum and maximum advertising interval, both in
         * units of (milliseconds * 1.6). The third parameter '7' sets advertising on all channels. */
        gecko_cmd_le_gap_set_adv_parameters(160,160,7);

        /* Start general advertising and enable connections. */
        gecko_cmd_le_gap_set_mode(le_gap_general_discoverable, le_gap_undirected_connectable);

        gecko_cmd_sm_set_bondable_mode(1);

        //hrHeartRateMeas.flags = (0 | 0 | 0x08 | 0x10);

        break;

      case gecko_evt_le_connection_opened_id:
    	  conConnectionId = evt->data.evt_le_connection_opened.connection;

            break;
      case gecko_evt_gatt_server_characteristic_status_id:
    	  if (0xff == conConnectionId)	break;
    	  if (evt->data.evt_gatt_server_characteristic_status.status_flags == 0x01 && evt->data.evt_gatt_server_characteristic_status.client_config_flags)
    	  {
			  if (gattdb_heart_rate_measurement == evt->data.evt_gatt_server_characteristic_status.characteristic)
			  {
				  gecko_cmd_hardware_set_soft_timer(TIMER_MS_2_TIMERTICK(1000),1,false);
				  //hrMeasure();
			  }
			  else if(gattdb_battery_level == evt->data.evt_gatt_server_characteristic_status.characteristic)
			  {
				  //batMeasure();
			  }
    	  }
    	  if(!evt->data.evt_gatt_server_characteristic_status.client_config_flags)
    	  {
    		  gecko_cmd_hardware_set_soft_timer(0,1,false);
    	  }
    	  break;
      case gecko_evt_hardware_soft_timer_id:
    	  switch (evt->data.evt_hardware_soft_timer.handle)
    	  {
    	  case 1:
    		  if(!ok)
    		  {
				hrm += 1;
				elc += 2;
				hrMeasure();
				batMeasure();
				//USART_Tx(BLEUSARTx,'A');
    		  }
			break;

    	  default :
    		  break;
    	  }
    	  break;
      case gecko_evt_le_connection_closed_id:

    	conConnectionId = 0xff;
	  
        /* Check if need to boot to dfu mode */
        if (boot_to_dfu)
        {
          /* Enter to DFU OTA mode */
          gecko_cmd_system_reset(2);
        }

        gecko_cmd_le_gap_set_adv_parameters(160,160,7);
		/* Start general advertising and enable connections. */
		gecko_cmd_le_gap_set_mode(le_gap_general_discoverable, le_gap_undirected_connectable);

		gecko_cmd_sm_set_bondable_mode(1);
        break;


      /* Events related to OTA upgrading
      ----------------------------------------------------------------------------- */

      /* Check if the user-type OTA Control Characteristic was written.
       * If ota_control was written, boot the device into Device Firmware Upgrade (DFU) mode. */
      case gecko_evt_gatt_server_user_write_request_id:
      
        if(evt->data.evt_gatt_server_user_write_request.characteristic==gattdb_ota_control)
        {
          /* Set flag to enter to OTA mode */
          boot_to_dfu = 1; 
          /* Send response to Write Request */
          gecko_cmd_gatt_server_send_user_write_response(
            evt->data.evt_gatt_server_user_write_request.connection, 
            gattdb_ota_control, 
            bg_err_success);
         
          /* Close connection to enter to DFU OTA mode */        
          gecko_cmd_endpoint_close(evt->data.evt_gatt_server_user_write_request.connection);
        }
        break;

      default:
        break;
    }
  }
  return 0;
}


/** @} (end addtogroup app) */
/** @} (end addtogroup Application) */
